{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **FlexDDM Python Package Jupyter Notebook Tutorial**\n",
    "This is a tutorial of how to use FlexDDM in action for results regarding how to fit models to participant data and how to validate the theoretical models that you create. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Before running this Jupyter notebook, make sure to install Python and Anaconda.** <br>\n",
    "\n",
    "#### <b><u>Python</u></b>\n",
    "Click the link [here](https://www.python.org/downloads/release/python-3120/) to the Python 3.12.0 distribution that we use that is compatible with this package. \n",
    "\n",
    "#### <b><u>Anaconda</u></b>\n",
    "Please make sure to create an environment in Anaconda. To do this, here are the steps: \n",
    "1. Download the Anaconda from this link [here](https://www.anaconda.com/download/success). Follow the installer instructions to correctly install the application. \n",
    "2. Go to the environments tab on the left hand side. Create a new environment by clicking the '+' sign and name it whatever you would like. In our case, we use flexddm. Once you create it, you should see some default packages already installed. \n",
    "<br><br> <img src=\"tutorial_images/environment.png\" alt=\"Environment\" style=\"width:600px;\"/> <br>\n",
    "<br> <img src=\"tutorial_images/create_environment.png\" alt=\"Environment\" style=\"width:600px;\"/> <br>\n",
    "<br> <img src=\"tutorial_images/create_environment_settings.png\" alt=\"Environment\" style=\"width:600px;\"/> <br> <br>\n",
    "3. There is a play button, click on it and click open with terminal. \n",
    "<br><br> <img src=\"tutorial_images/open_terminal.png\" alt=\"Environment\" style=\"width:600px;\"/> <br> <br>\n",
    "4. Use the `cd` command and locate the directory where the FlexDDM GitHub repository is in your computer. \n",
    "5. Type the following command into the terminal. Once the command is complete, you have created your environment! \n",
    "```bash\n",
    "      pip install -r requirements.txt\n",
    "```\n",
    "\n",
    "When running the Jupyter notebook, make sure to set the kernel to be the Anaconda environment you just created (in our case, it would be flexddm)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <b>Important Note </b>\n",
    "When using FlexDDM, make sure to maintain a similar directory structure as what it is currently. All Jupyter notebook files that fit and validate models should be at the same level where this tutorial file is (the first level of the FlexDDM repository but not inside any other directories). Any custom models that you would like to create can be created in the `flexddm/models` directory as a `py` file. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <b>Import Models and Functionality</b>\n",
    "The first line allows us to import the models that already exist in the package. The second import statement allows us to fit the models to experimental data and validate the models. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flexddm.models import DMC, DMCfs, DSTP, DSTPit, mDMC, mDMCfs, mDSTP, mDSTPit, mSSP, mSSPit, SSP, SSPit, StandardDDM\n",
    "from flexddm.main import fit, validation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <b>Fitting Models</b>\n",
    "#### <b>Fit Function</b>\n",
    "To fit models, we will utilize the `fit` function from the `main.py` file in the FlexDDM package. This is how to call `fit`: \n",
    "```py\n",
    "fit(models,  input_data, startingParticipants=None, endingParticipants=None, input_data_id=\"PPT\", input_data_congruency=\"Condition\", input_data_rt=\"RT\", input_data_accuracy=\"Correct\", output_fileName='output.csv', return_dataframes=False, posterior_predictive_check=True)\n",
    "```\n",
    "\n",
    "#### <b>Fit Function Parameters</b>\n",
    "##### <b> Two Required Parameters: </b> \n",
    "- **`models`** (*list*):a list of model objects that you would like to use <br><br>\n",
    "- **`input_data`** (*str / pd.DataFrame*): the participant data that you would like the models to fit to <br><br>\n",
    "    - *str:* file path for CSV file <br><br>\n",
    "    - *pd.DataFrame:* dataframe of the data\n",
    "\n",
    "##### <b>Optional Parameters:</b>\n",
    "\n",
    "If you want to specify a subset of participants to fit the models to, you can use the `startingParticipants` and `endingParticipants` parameters. When both `startingParticipants` and `endingParticipants` are `None`, it means that it will complete the fitting procedure for all participants. Please note that because of this feature, it is expected that all the participant IDs are in consecutive order (i.e. 1, 2, 3, 4, 5, and so on). \n",
    "\n",
    "- **`startingParticipants`** (*int*): the first participant of the subset <br><br>\n",
    "- **`endingParticipants`** (*int*): the last participant of the subset\n",
    "\n",
    "The next set of parameters are in regard to the format of the data. The standard format for the data contains 4 columns: **PPT** (Participant ID), **Condition** (Congruency- 0 for incongruent, 1 for congruent), **Correct** (Accuracy- 0 for incorrect, 1 for correct), and **RT** (Reaction time in seconds):\n",
    "\n",
    "<br>\n",
    "<img src=\"tutorial_images/sample_data.png\" alt=\"Environment\" style=\"width:600px;\"/>  \n",
    "<br>\n",
    "\n",
    "If your data has similar data but does not have the exact same columns, this works too! You can customize the parameters in the `fit` function that allows you to modify the column names to align with your data. <br><br>\n",
    "\n",
    "- **`input_data_id`** (*str*): the column name representing the participant ID <br><br>\n",
    "- **`input_data_congruency`** (*str*): the column name the Flanker task trial congruency <br><br>\n",
    "- **`input_data_rt`** (*str*): the column name representing the accuracy of the trial <br><br>\n",
    "- **`input_data_accuracy`** (*str*): the column name representing the accuracy of the trial <br><br>\n",
    "\n",
    "The next parameter is in regards to the output file. By default, every CSV will have the name `{model_name}_output.csv`. However, if you would like to change the name of the `output.csv`portion of the path, you can modify that using the output_fileName parameter. \n",
    "\n",
    "- **`output_fileName`** (*str*): the second portion of the CSV file path \n",
    "\n",
    "The next parameter tells whether or not you would like the dataframes which store the parameter values and model metrics. By default, this is set to `False`. \n",
    "\n",
    "- **`return_dataframes`** (*bool*): whether or not to return the dataframes \n",
    "\n",
    "The final parameter is in regards to whether or not you would like to see the posterior predictive graph for every participant. By default, this is set to `True`. \n",
    "\n",
    "- **`posterior_predictive_check`** (*bool*): whether or not to output the posterior predictive check plot \n",
    "\n",
    "Here is an example of what this looks like: \n",
    "<br><br>\n",
    "<img src=\"tutorial_images/posterior_predictive_check.png\" alt=\"Posterior Predictive Check\" style=\"width:600px;\"/>  \n",
    "<br>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to fit one model on all the participants in this dataset. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fit([SSP()], input_data='flexddm/data/hedge2018.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to fit multiple models on all the participants in this dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fit([SSP(), DMC(), DSTP()], input_data='flexddm/data/hedge2018.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to turn off posterior predictive checks. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fit([SSP(), DMC(), DSTP()], input_data='flexddm/data/hedge2018.csv', posterior_predictive_check=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to only receive the model fits for 5 participants. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fit([SSP(), DMC(), DSTP()], startingParticipants=1, endingParticipants=5, input_data='flexddm/data/hedge2018.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <b>Validating Models</b>\n",
    "#### <b>Validation Function</b>\n",
    "To validate models, we will utilize the `validation` function from the `main.py` file in the FlexDDM package. This is how to call `validation`: \n",
    "```py\n",
    "validation(models, model_recovery=True, model_recovery_simulations=100, parameter_recovery=True, param_recovery_simulations=100)\n",
    "```\n",
    "\n",
    "#### <b>Validation Function Parameters</b>\n",
    "##### <b>Required Parameter:</b>\n",
    "- **`models`** (*list*):a list of model objects correlating to the model that you would like to use <br>\n",
    "\n",
    "##### <b>Optional Parameters: </b>\n",
    "If you want to specify whether or not you would like to complete the model recovery functionality, you can use the `model_recovery` and `model_recovery_simulations` parameter. By default, the `model_recovery` is set to `True`, meaning that it will be completed, and `model_recovery_simulations` is set to 100, meaning that for 100 simulations will be run for every model. <br>\n",
    "- **`model_recovery`** (*bool*): whether or not to complete the model recovery functionality<br><br>\n",
    "- **`model_recovery_simulations`** (*int*): the number of simulations to run during model recovery <br>\n",
    "\n",
    "If you want to specify whether or not you would like to complete the parameter recovery functionality, you can use the `parameter_recovery` and `parameter_recovery_simulations` parameter. By default, the `parameter_recovery` is set to `True`, meaning that it will be completed, and `parameter_recovery_simulations` is set to 100, meaning that for 100 simulations will be run for every model. <br>\n",
    "- **`parameter_recovery`** (*bool*): whether or not to complete the parameter recovery functionality<br><br>\n",
    "- **`parameter_recovery_simulations`** (*int*): the number of simulations to run during parameter recovery <br><br>\n",
    "\n",
    "If both model recovery and parameter recovery functionalities are to be completed, model recovery will occur first, then parameter recovery. <br><br>\n",
    "\n",
    "All plots created from model and parameter recovery will all be saved into a directory called `validation`. The model validation heatmap will be saved in the `model_validation.png` file. The parameter validation plots will be in subdirectories in the following format: `parameter_validation/{model_name}/{parameter_name}.png`. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to validate three models with both parameter and model recovery. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "validation(models=[DMCfs(), mDMC(), SSPit()])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to specify the number of simulations for parameter and model recovery (outside of the default 100)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "validation(models=[DMCfs(), mDMC(), mSSPit()], model_recovery_simulations=200, param_recovery_simulations=75)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to specify that you do not want to complete model recovery. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "validation(models=[DMCfs(), mDMC(), mSSPit()], model_recovery=False, param_recovery_simulations=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### This is how to specify that you do not want to complete parameter recovery. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "validation(models=[DMCfs(), mDMC(), mSSPit()], param_recovery=False)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "flexddm",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
